package com.lancoo.edu.platform.operation.commons.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.lancoo.edu.platform.operation.commons.domain.api.user.OnlineUserInfo;
import com.lancoo.edu.platform.operation.commons.service.api.UserInfoApiService;
import com.lancoo.edu.platform.operation.commons.annotation.CheckToken;
import com.lancoo.edu.platform.operation.commons.constant.SystemConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 * Token 拦截器
 * @author pky
 */
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    UserInfoApiService userInfoApiService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        // 从 http 请求头中取出 token
        String token = request.getHeader(SystemConstant.HEADER_AUTH);
        // 如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        // 检查用户权限的注解
        if (method.isAnnotationPresent(CheckToken.class)) {
            CheckToken checkToken = method.getAnnotation(CheckToken.class);
            if (checkToken.required()) {
                return checkToken(request, response, token);
            }
        }
        return true;
    }

    /**
     * 校验 token
     * @param request 请求
     * @param token 令牌
     * @return 校验结果，true/通过；false/不通过
     * @throws Exception 可能出现的异常
     */
    private boolean checkToken(HttpServletRequest request, HttpServletResponse response, String token) throws Exception {
        // ----  避免前端出现无法获取返回结果的情况，以下校验不通过不进行抛出异常，直接设置返回 ---- //
        // 执行认证
        if (StringUtils.isBlank(token)) {
            log.error(request.getContextPath() + "：token为空");
            setResultJson(response, "token 不可为空");
            return false;
        }
        if(token.contains("X-Token=")) {
            token = token.substring(token.indexOf("X-Token=") + 8);
        }
        // 基础平台获取用户信息
        OnlineUserInfo userInfo = userInfoApiService.getOnlineUserInfo(token);
        if(userInfo == null || StringUtils.isBlank(userInfo.getUserId())) {
            log.error(request.getContextPath() + "：token认证失败：" + token);
            setResultJson(response, "token 认证失败");
            return false;
        }
        request.setAttribute(SystemConstant.ATTRIBUTE_USER, userInfo);
        return true;
    }

    /**
     * 设置响应json数据
     * @param response 响应
     * @param msg 返回说明
     * @throws Exception 可能出现的异常
     */
    private void setResultJson(HttpServletResponse response, String msg) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        PrintWriter writer = response.getWriter();
        JSONObject resultJson = new JSONObject();
        resultJson.put("code", 401);
        resultJson.put("msg", msg);
        writer.append(resultJson.toJSONString());
    }
}
